use async_trait::async_trait;
use my_rust_core::{
    constants,
    shared::{self, date_helper},
};
use std::sync::Arc;

use sea_orm::{
    ColumnTrait, DatabaseConnection, DbErr, EntityTrait, PaginatorTrait, QueryFilter, QuerySelect,
    Set,
};

use crate::entities;

#[async_trait]
pub trait RoleService: Send + Sync {
    /// Initializes the role table with default roles.
    async fn init(&self) -> Result<(), DbErr>;

    /// Queries the role id by authority.
    /// Authority. AKA role name.
    async fn query_id(&self, authority: &str) -> Result<Option<String>, DbErr>;
}

pub struct RoleServiceImpl {
    db: Arc<DatabaseConnection>,
}

impl RoleServiceImpl {
    pub fn new(db: Arc<DatabaseConnection>) -> Self {
        RoleServiceImpl { db }
    }
}

#[async_trait]
impl RoleService for RoleServiceImpl {
    async fn init(&self) -> Result<(), DbErr> {
        let count = entities::prelude::Role::find()
            .count(self.db.as_ref())
            .await?;

        if count == 0 {
            let models = [
                entities::role::ActiveModel {
                    id: Set(shared::util::generate_uuid_as_hex_string()),
                    authority: Set(constants::role::ROLE_SYSTEM_ADMIN.to_owned()),
                    title: Set(String::from("系统管理员")),
                    description: Set(Some(String::from("当前整个系统的管理员，不属于任何账户。"))),
                    date_created: Set(date_helper::get_current_naive_date_time()),
                    ..Default::default()
                },
                entities::role::ActiveModel {
                    id: Set(shared::util::generate_uuid_as_hex_string()),
                    authority: Set(constants::role::ROLE_ACCOUNT_GROUP_ADMIN.to_owned()),
                    title: Set(String::from("账户管理员")),
                    description: Set(Some(String::from(
                        "可对当前账户组下的各项，如银行卡片和收支类别等进行管理。",
                    ))),
                    date_created: Set(date_helper::get_current_naive_date_time()),
                    ..Default::default()
                },
                entities::role::ActiveModel {
                    id: Set(shared::util::generate_uuid_as_hex_string()),
                    authority: Set(constants::role::ROLE_ACCOUNT_GROUP_USER.to_owned()),
                    title: Set(String::from("用户")),
                    description: Set(Some(String::from("账户组普通用户"))),
                    date_created: Set(date_helper::get_current_naive_date_time()),
                    ..Default::default()
                },
                entities::role::ActiveModel {
                    id: Set(shared::util::generate_uuid_as_hex_string()),
                    authority: Set(constants::role::ROLE_ACCOUNT_GROUP_VIEWER.to_owned()),
                    title: Set(String::from("查看者")),
                    description: Set(Some(String::from(
                        "账户组只读用户，仅可查看，不可操作数据。",
                    ))),
                    date_created: Set(date_helper::get_current_naive_date_time()),
                    ..Default::default()
                },
            ];

            entities::prelude::Role::insert_many(models)
                .exec(self.db.as_ref())
                .await?;
        }

        Ok(())
    }

    /// Queries the role id by authority.
    /// Authority. AKA role name.
    async fn query_id(&self, authority: &str) -> Result<Option<String>, DbErr> {
        let id: Option<String> = entities::prelude::Role::find()
            .select_only()
            .column(entities::role::Column::Id)
            .filter(entities::role::Column::Authority.eq(authority))
            .into_tuple()
            .one(self.db.as_ref())
            .await?
            .unwrap();

        Ok(id)
    }
}
